//=============================================================================
#include "CApp.h"

//=============================================================================
void CApp::OnLoop() {
    CFPS::FPSControl.OnLoop();

    CLua::LuaControl.PushFunction("OnLoop");
    CLua::LuaControl.Call();

    CClients*       Client = NULL;C:

    for(unsigned int i = 0;i < MAX_CLIENTS;i++) {
        Client = &CClients::Clients[i];

        if(Client->IsAvailable()) continue;

        for(unsigned int j = 0;j < Client->Packets.size();j++) {
            Packet = &Client->Packets[j];

            if(Packet->IsReady() == false) continue;

            switch(Client->GetMode()) {
                case CCLIENTS_MODE_LOGIN: {
                    if(Packet->GetMessageID() == CNETWORK_MESSAGE_LOGIN) {
                        CLog::Notice("Client Login with UID " + Packet->GetDataString());

                        Client->UID = Packet->GetDataString();

                        CNetworkStream::SendHeader(Client->GetSocket(), CNETWORK_MESSAGE_LOGIN_OK, 0);
                    }

                    Client->SetMode(CCLIENTS_MODE_GETFILELIST);

                    break;
                }

                case CCLIENTS_MODE_UPDATE: {
                    if(Packet->GetMessageID() == CNETWORK_MESSAGE_UPDATE_PLAYER) {
                        std::vector<std::string> Parts = StringifyExplode(Packet->GetDataString(), " ");

                        std::string PlayerIDString = Parts[0];

                        int ThisPlayerID = atoi(PlayerIDString.c_str());

                        CPlayer::PlayerList[ThisPlayerID].Unserialize(Packet->GetDataString());
                    }

                    break;
                }
            }
        }

        switch(Client->GetMode()) {
            case CCLIENTS_MODE_GETFILELIST: {
                Client->ScanFiles();

                for(int i = 0;i < Client->Files.size();i++) {
                    std::string FilePacket = Client->Files[i].Filename + " " + Stringify(Client->Files[i].TotalBytes) +  " " + Client->Files[i].Checksum + " " + Stringify(Client->Files[i].IsFolder);

                    CNetworkStream::SendHeader(Client->GetSocket(), CNETWORK_MESSAGE_FILELIST, FilePacket.size());
                    CNetworkStream::SendString(Client->GetSocket(), FilePacket);
                }

                CNetworkStream::SendHeader(Client->GetSocket(), CNETWORK_MESSAGE_FILELIST_DONE, 0);

                Client->SetMode(CCLIENTS_MODE_SENDFILES);

                break;
            }

            case CCLIENTS_MODE_SENDFILES: {
                Uint8 Buffer[CNETWORKPACKET_DATA_SIZE];

                for(int i = Client->Files.size() - 1;i >= 0;i--) {
                    CClientsFiles* File = &Client->Files[i];

                    if(File->State == CCLIENTSFILES_STATE_IGNORE) {
                        Client->Files.pop_back();
                        continue;
                    }

                    FILE* FileHandle = fopen(File->Filename.c_str(), "rb");

                    fseek(FileHandle, File->BytesSent, SEEK_SET);

                    for(unsigned int i = 0;i < 10;i++) {
                        int BytesToRead = 0;

                        if(File->TotalBytes - File->BytesSent < CNETWORKPACKET_DATA_SIZE)   BytesToRead = (File->TotalBytes - File->BytesSent);
                        else                                                                BytesToRead = CNETWORKPACKET_DATA_SIZE;

                        fread(Buffer, 1, BytesToRead, FileHandle);

                        CNetworkStream::SendHeader(Client->GetSocket(), CNETWORK_MESSAGE_FILE, BytesToRead);
                        CNetworkStream::SendData(Client->GetSocket(), Buffer, BytesToRead);

                        File->BytesSent += BytesToRead;

                        if(File->BytesSent == File->TotalBytes) break;
                    }

                    fclose(FileHandle);

                    if(File->BytesSent == File->TotalBytes) {
                        CNetworkStream::SendHeader(Client->GetSocket(), CNETWORK_MESSAGE_FILE_DONE, 0);
                        Client->Files.pop_back();
                    }

                    break;
                }

                if(Client->Files.size() <= 0) {
                    Client->SetMode(CCLIENTS_MODE_ENTER_WORLD);
                }

                break;
            }

            case CCLIENTS_MODE_ENTER_WORLD: {
                std::string Packet = Stringify(Client->PlayerID);

                CNetworkStream::SendHeader(Client->GetSocket(), CNETWORK_MESSAGE_ENTER_WORLD, Packet.size());
                CNetworkStream::SendString(Client->GetSocket(), Packet);

                Client->PlayerID = CPlayer::Connect(Client->UID);

                CLua::LuaControl.PushFunction("OnEvent");
                CLua::LuaControl.PushArgNumber(EVENT_PLAYER_LOGGED_IN);
                CLua::LuaControl.PushArgNumber(Client->PlayerID);
                CLua::LuaControl.PushArgNumber(0);
                CLua::LuaControl.Call();

                Client->SetMode(CCLIENTS_MODE_UPDATE);

                break;
            }

            case CCLIENTS_MODE_UPDATE: {
                if(Client->LastUpdate + 20 > SDL_GetTicks()) break;

                Client->LastUpdate = SDL_GetTicks();

                CPlayer* Player = &CPlayer::PlayerList[Client->PlayerID];

                std::vector<CPlayer*> Players = Player->GetPlayersInProximity();

                for(unsigned int i = 0;i < Players.size();i++) {
                    if(Players[i]->ID == Client->PlayerID) continue;

                    std::string Packet;

                    Packet = Players[i]->Serialize();

                    CNetworkStream::SendHeader(Client->GetSocket(), CNETWORK_MESSAGE_UPDATE_PLAYER, Packet.size());
                    CNetworkStream::SendString(Client->GetSocket(), Packet);
                }

                break;
            }
        }

        for(int j = Client->Packets.size() - 1;j >= 0;j--) {
            CNetworkPacket* Packet = &Client->Packets[j];

            if(Packet->IsReady()) Client->Packets.erase(Client->Packets.begin() + j);
        }
    }
}

//=============================================================================
